package service

import (
	"errors"
	"fmt"
	"time"

	"github.com/slrun/callcenter/internal/model"
	"go.mongodb.org/mongo-driver/bson"
	"go.mongodb.org/mongo-driver/mongo"
	"go.mongodb.org/mongo-driver/mongo/options"
)

// TicketService 工单服务
type TicketService struct {
	MongoDB            *mongo.Database
	AgentService       *AgentService
	CallControlService *CallControlService
}

// NewTicketService 创建工单服务实例
func NewTicketService(mongoDB *mongo.Database, agentService *AgentService, callControlService *CallControlService) *TicketService {
	return &TicketService{
		MongoDB:            mongoDB,
		AgentService:       agentService,
		CallControlService: callControlService,
	}
}

// CreateTicket 创建工单
func (s *TicketService) CreateTicket(req model.TicketCreateRequest, creatorID, creatorName string) (*model.Ticket, error) {
	// 生成工单ID
	ticketID := fmt.Sprintf("TKT%d%d", time.Now().Unix(), time.Now().UnixNano()%1000)

	// 创建工单实例
	ticket := &model.Ticket{
		ID:            ticketID,
		Title:         req.Title,
		Description:   req.Description,
		Status:        model.TicketStatusNew,
		Priority:      req.Priority,
		Type:          req.Type,
		Source:        req.Source,
		CustomerID:    req.CustomerID,
		CustomerName:  req.CustomerName,
		CustomerPhone: req.CustomerPhone,
		CustomerEmail: req.CustomerEmail,
		DepartmentID:  req.DepartmentID,
		Tags:          req.Tags,
		RelatedCallID: req.RelatedCallID,
		DueDate:       req.DueDate,
		CreatorID:     creatorID,
		CreatorName:   creatorName,
		Comments:      []model.TicketComment{},
		Attachments:   []model.Attachment{},
		Metadata:      req.Metadata,
		CreatedAt:     time.Now(),
		UpdatedAt:     time.Now(),
	}

	// 如果没有指定优先级，设置默认优先级
	if ticket.Priority == "" {
		ticket.Priority = model.TicketPriorityMedium
	}

	// 如果指定了分配人，执行工单分配
	if req.AssignedToID != "" {
		if err := s.assignTicket(ticket, req.AssignedToID, creatorID, creatorName, "工单创建时分配"); err != nil {
			return nil, fmt.Errorf("分配工单失败: %w", err)
		}
	}

	// 保存到数据库
	collection := s.MongoDB.Collection("tickets")
	if _, err := collection.InsertOne(nil, ticket); err != nil {
		return nil, fmt.Errorf("创建工单失败: %w", err)
	}

	// 记录工单历史
	if err := s.recordTicketHistory(ticket.ID, "status", "", string(ticket.Status), creatorID, creatorName); err != nil {
		// 记录失败只记录日志，不影响工单创建
		fmt.Printf("记录工单历史失败: %v\n", err)
	}

	return ticket, nil
}

// GetTicket 获取工单详情
func (s *TicketService) GetTicket(ticketID string) (*model.Ticket, error) {
	collection := s.MongoDB.Collection("tickets")
	var ticket model.Ticket

	filter := bson.M{"_id": ticketID}
	if err := collection.FindOne(nil, filter).Decode(&ticket); err != nil {
		if errors.Is(err, mongo.ErrNoDocuments) {
			return nil, errors.New("工单不存在")
		}
		return nil, fmt.Errorf("获取工单失败: %w", err)
	}

	return &ticket, nil
}

// UpdateTicket 更新工单
func (s *TicketService) UpdateTicket(ticketID string, req model.TicketUpdateRequest, updatedByID, updatedByName string) (*model.Ticket, error) {
	// 获取现有工单
	ticket, err := s.GetTicket(ticketID)
	if err != nil {
		return nil, err
	}

	// 构建更新字段和记录历史
	updates := bson.M{}
	if req.Title != "" && req.Title != ticket.Title {
		if err := s.recordTicketHistory(ticketID, "title", ticket.Title, req.Title, updatedByID, updatedByName); err != nil {
			fmt.Printf("记录工单历史失败: %v\n", err)
		}
		updates["title"] = req.Title
	}

	if req.Description != "" && req.Description != ticket.Description {
		if err := s.recordTicketHistory(ticketID, "description", ticket.Description, req.Description, updatedByID, updatedByName); err != nil {
			fmt.Printf("记录工单历史失败: %v\n", err)
		}
		updates["description"] = req.Description
	}

	if req.Status != "" && req.Status != ticket.Status {
		if err := s.recordTicketHistory(ticketID, "status", string(ticket.Status), string(req.Status), updatedByID, updatedByName); err != nil {
			fmt.Printf("记录工单历史失败: %v\n", err)
		}
		updates["status"] = req.Status

		// 如果状态变为已解决，记录解决时间
		if req.Status == model.TicketStatusResolved && ticket.ResolutionTime.IsZero() {
			updates["resolution_time"] = time.Now()
		}
	}

	if req.Priority != "" && req.Priority != ticket.Priority {
		if err := s.recordTicketHistory(ticketID, "priority", string(ticket.Priority), string(req.Priority), updatedByID, updatedByName); err != nil {
			fmt.Printf("记录工单历史失败: %v\n", err)
		}
		updates["priority"] = req.Priority
	}

	if req.Type != "" && req.Type != ticket.Type {
		if err := s.recordTicketHistory(ticketID, "type", string(ticket.Type), string(req.Type), updatedByID, updatedByName); err != nil {
			fmt.Printf("记录工单历史失败: %v\n", err)
		}
		updates["type"] = req.Type
	}

	if req.DepartmentID != "" && req.DepartmentID != ticket.DepartmentID {
		if err := s.recordTicketHistory(ticketID, "department_id", ticket.DepartmentID, req.DepartmentID, updatedByID, updatedByName); err != nil {
			fmt.Printf("记录工单历史失败: %v\n", err)
		}
		updates["department_id"] = req.DepartmentID
	}

	if req.Tags != nil {
		if err := s.recordTicketHistory(ticketID, "tags", fmt.Sprintf("%v", ticket.Tags), fmt.Sprintf("%v", req.Tags), updatedByID, updatedByName); err != nil {
			fmt.Printf("记录工单历史失败: %v\n", err)
		}
		updates["tags"] = req.Tags
	}

	if !req.DueDate.IsZero() && req.DueDate != ticket.DueDate {
		if err := s.recordTicketHistory(ticketID, "due_date", ticket.DueDate.Format(time.RFC3339), req.DueDate.Format(time.RFC3339), updatedByID, updatedByName); err != nil {
			fmt.Printf("记录工单历史失败: %v\n", err)
		}
		updates["due_date"] = req.DueDate
	}

	if req.Resolution != "" && req.Resolution != ticket.Resolution {
		if err := s.recordTicketHistory(ticketID, "resolution", ticket.Resolution, req.Resolution, updatedByID, updatedByName); err != nil {
			fmt.Printf("记录工单历史失败: %v\n", err)
		}
		updates["resolution"] = req.Resolution
	}

	if req.Metadata != nil {
		updates["metadata"] = req.Metadata
	}

	// 更新时间戳
	updates["updated_at"] = time.Now()

	// 执行更新
	collection := s.MongoDB.Collection("tickets")
	filter := bson.M{"_id": ticketID}
	update := bson.M{"$set": updates}

	if _, err := collection.UpdateOne(nil, filter, update); err != nil {
		return nil, fmt.Errorf("更新工单失败: %w", err)
	}

	// 返回更新后的工单
	return s.GetTicket(ticketID)
}

// AssignTicket 分配工单
func (s *TicketService) AssignTicket(ticketID string, req model.TicketAssignRequest, assignedByID, assignedByName string) (*model.Ticket, error) {
	// 获取现有工单
	ticket, err := s.GetTicket(ticketID)
	if err != nil {
		return nil, err
	}

	// 执行分配
	if err := s.assignTicket(ticket, req.AssignedToID, assignedByID, assignedByName, req.Reason); err != nil {
		return nil, err
	}

	// 更新数据库
	collection := s.MongoDB.Collection("tickets")
	filter := bson.M{"_id": ticketID}
	update := bson.M{"$set": bson.M{
		"assigned_to_id":   req.AssignedToID,
		"assigned_to_name": ticket.AssignedToName, // 已在assignTicket中设置
		"updated_at":       time.Now(),
	}}

	if _, err := collection.UpdateOne(nil, filter, update); err != nil {
		return nil, fmt.Errorf("更新工单分配失败: %w", err)
	}

	// 如果工单状态是新建，自动改为已打开
	if ticket.Status == model.TicketStatusNew {
		updateStatus := bson.M{
			"$set": bson.M{
				"status":     model.TicketStatusOpen,
				"updated_at": time.Now(),
			},
		}
		collection.UpdateOne(nil, filter, updateStatus)

		// 记录状态变更历史
		s.recordTicketHistory(ticketID, "status", string(model.TicketStatusNew), string(model.TicketStatusOpen), assignedByID, assignedByName)
	}

	return s.GetTicket(ticketID)
}

// SearchTickets 搜索工单
func (s *TicketService) SearchTickets(criteria model.TicketSearchCriteria) ([]model.Ticket, int64, error) {
	collection := s.MongoDB.Collection("tickets")
	filter := bson.M{}

	// 构建查询条件
	if criteria.Title != "" {
		filter["title"] = bson.M{"$regex": criteria.Title, "$options": "i"}
	}
	if criteria.Status != "" {
		filter["status"] = criteria.Status
	}
	if criteria.Priority != "" {
		filter["priority"] = criteria.Priority
	}
	if criteria.Type != "" {
		filter["type"] = criteria.Type
	}
	if criteria.Source != "" {
		filter["source"] = criteria.Source
	}
	if criteria.CustomerID != "" {
		filter["customer_id"] = criteria.CustomerID
	}
	if criteria.CustomerName != "" {
		filter["customer_name"] = bson.M{"$regex": criteria.CustomerName, "$options": "i"}
	}
	if criteria.AssignedToID != "" {
		filter["assigned_to_id"] = criteria.AssignedToID
	}
	if criteria.DepartmentID != "" {
		filter["department_id"] = criteria.DepartmentID
	}
	if criteria.Tag != "" {
		filter["tags"] = criteria.Tag
	}
	if criteria.RelatedCallID != "" {
		filter["related_call_id"] = criteria.RelatedCallID
	}
	if criteria.CreatorID != "" {
		filter["creator_id"] = criteria.CreatorID
	}

	// 日期范围查询
	if !criteria.StartDate.IsZero() {
		filter["created_at"] = bson.M{"$gte": criteria.StartDate}
	}
	if !criteria.EndDate.IsZero() {
		if _, ok := filter["created_at"]; ok {
			filter["created_at"].(bson.M)["$lte"] = criteria.EndDate
		} else {
			filter["created_at"] = bson.M{"$lte": criteria.EndDate}
		}
	}

	if !criteria.DueDateFrom.IsZero() {
		filter["due_date"] = bson.M{"$gte": criteria.DueDateFrom}
	}
	if !criteria.DueDateTo.IsZero() {
		if _, ok := filter["due_date"]; ok {
			filter["due_date"].(bson.M)["$lte"] = criteria.DueDateTo
		} else {
			filter["due_date"] = bson.M{"$lte": criteria.DueDateTo}
		}
	}

	// 计算总数
	var total int64
	var err error
	total, err = collection.CountDocuments(nil, filter, nil)
	if err != nil {
		return nil, 0, fmt.Errorf("计算工单总数失败: %w", err)
	}

	// 分页和排序
	page := criteria.Page
	if page < 1 {
		page = 1
	}
	pageSize := criteria.PageSize
	if pageSize < 1 || pageSize > 100 {
		pageSize = 20
	}
	skip := (page - 1) * pageSize

	// 排序
	sortField := criteria.SortBy
	if sortField == "" {
		sortField = "created_at"
	}
	sortOrder := criteria.SortOrder
	if sortOrder == "" {
		sortOrder = "desc"
	}

	sort := bson.M{sortField: 1}
	if sortOrder == "desc" {
		sort[sortField] = -1
	}

	// 查询数据
	skipValue := int64(skip)
	limitValue := int64(pageSize)
	cursor, err := collection.Find(nil, filter, &options.FindOptions{
		Skip:  &skipValue,
		Limit: &limitValue,
		Sort:  sort,
	})
	if err != nil {
		return nil, 0, fmt.Errorf("搜索工单失败: %w", err)
	}
	defer cursor.Close(nil)

	var tickets []model.Ticket
	if err := cursor.All(nil, &tickets); err != nil {
		return nil, 0, fmt.Errorf("解析工单数据失败: %w", err)
	}

	return tickets, total, nil
}

// AddComment 添加工单评论
func (s *TicketService) AddComment(ticketID string, req model.TicketCommentRequest, authorID, authorName string) (*model.Ticket, error) {
	// 生成评论ID
	commentID := fmt.Sprintf("CMM%d%d", time.Now().Unix(), time.Now().UnixNano()%1000)

	// 创建评论
	comment := model.TicketComment{
		ID:          commentID,
		Content:     req.Content,
		AuthorID:    authorID,
		AuthorName:  authorName,
		IsPrivate:   req.IsPrivate,
		CreatedAt:   time.Now(),
		Attachments: []model.Attachment{},
	}

	// 添加评论到工单
	collection := s.MongoDB.Collection("tickets")
	filter := bson.M{"_id": ticketID}
	update := bson.M{"$push": bson.M{"comments": comment}}

	if _, err := collection.UpdateOne(nil, filter, update); err != nil {
		return nil, fmt.Errorf("添加评论失败: %w", err)
	}

	return s.GetTicket(ticketID)
}

// GetTicketStatistics 获取工单统计
func (s *TicketService) GetTicketStatistics() (*model.TicketStatistics, error) {
	collection := s.MongoDB.Collection("tickets")
	stats := &model.TicketStatistics{
		ByStatus:     make(map[string]int64),
		ByPriority:   make(map[string]int64),
		ByType:       make(map[string]int64),
		ByDepartment: make(map[string]int64),
	}

	// 统计总工单数量
	total, err := collection.CountDocuments(nil, bson.M{})
	if err != nil {
		return nil, fmt.Errorf("统计工单总数失败: %w", err)
	}
	stats.TotalTickets = total

	// 按状态统计
	statusCursor, err := collection.Aggregate(nil, []bson.M{
		{"$group": bson.M{"_id": "$status", "count": bson.M{"$sum": 1}}},
	})
	if err != nil {
		return nil, fmt.Errorf("按状态统计工单失败: %w", err)
	}
	defer statusCursor.Close(nil)

	var statusResults []bson.M
	if err := statusCursor.All(nil, &statusResults); err != nil {
		return nil, fmt.Errorf("解析状态统计结果失败: %w", err)
	}

	for _, result := range statusResults {
		status := result["_id"].(string)
		count := result["count"].(int64)
		stats.ByStatus[status] = count

		// 计算未关闭工单数量
		if status != string(model.TicketStatusClosed) && status != string(model.TicketStatusCancelled) {
			stats.OpenTickets += count
		}
	}

	// 计算过期工单数量
	today := time.Now()
	overdue, err := collection.CountDocuments(nil, bson.M{
		"due_date": bson.M{"$lt": today},
		"status":   bson.M{"$nin": []string{string(model.TicketStatusClosed), string(model.TicketStatusCancelled)}},
	})
	if err != nil {
		return nil, fmt.Errorf("统计过期工单失败: %w", err)
	}
	stats.OverdueTickets = overdue

	// 统计今日新建工单
	todayStart := time.Date(today.Year(), today.Month(), today.Day(), 0, 0, 0, 0, today.Location())
	todayCount, err := collection.CountDocuments(nil, bson.M{
		"created_at": bson.M{"$gte": todayStart},
	})
	if err != nil {
		return nil, fmt.Errorf("统计今日工单失败: %w", err)
	}
	stats.TodayTickets = todayCount

	return stats, nil
}

// 内部方法：分配工单
func (s *TicketService) assignTicket(ticket *model.Ticket, assignedToID, assignedByID, assignedByName, reason string) error {
	// 跳过座席信息获取，不需要agent变量

	// 记录分配历史
	assignment := model.TicketAssignment{
		ID:             fmt.Sprintf("ASN%d%d", time.Now().Unix(), time.Now().UnixNano()%1000),
		TicketID:       ticket.ID,
		AssignedToID:   assignedToID,
		AssignedToName: "系统分配",
		AssignedByID:   assignedByID,
		AssignedByName: assignedByName,
		AssignedAt:     time.Now(),
		Reason:         reason,
	}

	// 保存分配历史
	assignmentCollection := s.MongoDB.Collection("ticket_assignments")
	if _, err := assignmentCollection.InsertOne(nil, assignment); err != nil {
		return fmt.Errorf("保存工单分配历史失败: %w", err)
	}

	// 更新工单的分配信息
	ticket.AssignedToID = assignedToID
	ticket.AssignedToName = "系统分配"

	return nil
}

// 内部方法：记录工单历史
func (s *TicketService) recordTicketHistory(ticketID, fieldName, oldValue, newValue, changedByID, changedByName string) error {
	if oldValue == newValue {
		return nil // 没有变化，无需记录
	}

	history := model.TicketHistory{
		ID:            fmt.Sprintf("HST%d%d", time.Now().Unix(), time.Now().UnixNano()%1000),
		TicketID:      ticketID,
		FieldName:     fieldName,
		OldValue:      oldValue,
		NewValue:      newValue,
		ChangedByID:   changedByID,
		ChangedByName: changedByName,
		CreatedAt:     time.Now(),
	}

	collection := s.MongoDB.Collection("ticket_history")
	_, err := collection.InsertOne(nil, history)
	return err
}
